/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  deque.h
 *        \brief  This is a general-purpose C language deque module, with circular mode and common data structure
 *       \author  Lamdonn
 *        \email  Lamdonn@163.com
 *      \version  1.1.0
 *      \license  GPL2
 *    \copyright  Copyright (C) 2023 Lamdonn.
 ********************************************************************************************************/
#ifndef __deque_H
#define __deque_H

#include "iterator.h"
#include <stdlib.h>

/* deque type define */
typedef struct
{
    VOBJECT parent;                     /* parent object */
    int capacity;                       /* capacity of deque */
    int head;                           /* index of deque head */
    int tail;                           /* index of deque tail */
    int mode;                           /* control mode */
} DEQUE, *deque_t;

/* deque orgin define */
#define DEQUE_ORGIN_FRONT               (1)
#define DEQUE_ORGIN_BACK                (0)

/* control mode */
#define DEQUE_MODE_DEFAULT              (0)         /* default mode */
#define DEQUE_MODE_READ                 (1u << 0)   /* readable mode */
#define DEQUE_MODE_MODIFY               (1u << 1)   /* modifiable mode */
#define DEQUE_MODE_OVERWRITE            (1u << 2)   /* overwrite mode, when the deque is full, the new data overwrites the old data */
#define DEQUE_MODE_POP_RESET            (1u << 3)   /* pop data and reset item */
#define DEQUE_MODE_POP_HOLD             (1u << 4)   /* pop data but not delete */
#define DEQUE_MODE_LMT_PUSH             (1u << 5)   /* limit push */
#define DEQUE_MODE_LMT_POP              (1u << 6)   /* limit pop */
#define DEQUE_MODE_RESIZE               (1u << 7)   /* resize */
#define DEQUE_MODE_DROP_FRONT           (1u << 8)   /* when reducing the deque, the front is lost first */

/* set way */
#define DEQUE_SET_MODE                  (1)
#define DEQUE_RESET_MODE                (0)

/** 
 *  \brief initialize deque
 *  \param[in] deque: deque handler
 *  \param[in] array: address of array
 *  \param[in] dsize: size of deque item
 *  \param[in] capacity: capacity of deque
 *  \return 1: success or 0: fail
 */
int deque_init(deque_t deque, void* array, int dsize, int capacity);

/** 
 *  \brief deinit deque
 *  \param[in] deque: deque handler
 *  \return none
 */
void deque_deinit(deque_t deque);

/** 
 *  \brief create deque
 *  \param[in] dsize: size of deque items
 *  \param[in] capacity: capacity of deque
 *  \return deque handler or NULL: fail
 */
deque_t deque_create(int dsize, int capacity);

/** 
 *  \brief delete deque created by deque_create function
 *  \param[in] deque: deque handler
 *  \return none
 */
void deque_delete(deque_t deque);

/** 
 *  \brief judge whether the deque is empty
 *  \param[in] deque: deque handler
 *  \return 1: empty or 0: not empty
 */
int deque_empty(deque_t deque);

/** 
 *  \brief check whether the deque is full
 *  \param[in] deque: deque handler
 *  \return 1: full or 0: not full
 */
int deque_full(deque_t deque);

/** 
 *  \brief get current items size
 *  \param[in] deque: deque handler
 *  \return size of item
 */
int deque_size(deque_t deque);

/** 
 *  \brief deque items join the deque from the head
 *  \param[in] deque: deque handler
 *  \param[in] data: address of deque item data
 *  \return 1: success or 0: fail
 */
int deque_push_front(deque_t deque, void* data);

/** 
 *  \brief deque items join the deque from the tail
 *  \param[in] deque: deque handler
 *  \param[in] data: address of deque item data
 *  \return 1: success or 0: fail
 */
int deque_push_back(deque_t deque, void* data);

/** 
 *  \brief deque items pop up the deque from the head
 *  \param[in] deque: deque handler
 *  \param[out] data: address of deque item data
 *  \return 1: success or 0: fail
 */
int deque_pop_front(deque_t deque, void* data);

/** 
 *  \brief deque items pop up the deque from the tail
 *  \param[in] deque: deque handler
 *  \param[out] data: address of deque item data
 *  \return 1: success or 0: fail
 */
int deque_pop_back(deque_t deque, void* data);

/** 
 *  \brief clear deque
 *  \param[in] deque: deque handler
 *  \return none
 */
void deque_clear(deque_t deque);

/** 
 *  \brief get the pointer of deque's item
 *  \param[in] deque: deque handler
 *  \param[in] index: deque index
 *  \param[in] orgin: DEQUE_ORGIN_FRONT or DEQUE_ORGIN_BACK
 *  \return pointer of deque's item
 */
void* deque_data(deque_t deque, int index, int orgin);

/** 
 *  \brief insert data to deque
 *  \param[in] deque: deque handler
 *  \param[in] index: deque index
 *  \param[in] data: address of deque item data
 *  \param[in] orgin: DEQUE_ORGIN_FRONT or DEQUE_ORGIN_BACK
 *  \return 1: success or 0: fail
 */
int deque_insert(deque_t deque, int index, void* data, int orgin);

/** 
 *  \brief erase items from the deque
 *  \param[in] deque: deque handler
 *  \param[in] begin: begin index of deque
 *  \param[in] end: end index of deque
 *  \param[in] orgin: DEQUE_ORGIN_FRONT or DEQUE_ORGIN_BACK
 *  \return 1: success or 0: fail
 */
int deque_erase(deque_t deque, int begin, int end, int orgin);

/** 
 *  \brief read the data of deque
 *  \param[in] deque: deque handler
 *  \param[in] index: deque index
 *  \param[out] data: address of deque item data
 *  \param[in] orgin: DEQUE_ORGIN_FRONT or DEQUE_ORGIN_BACK
 *  \return 1: success or 0: fail
 */
int deque_read(deque_t deque, int index, void* data, int orgin);

/** 
 *  \brief modify the data of deque
 *  \param[in] deque: deque handler
 *  \param[in] index: deque index
 *  \param[in] data: address of deque item data
 *  \param[in] orgin: DEQUE_ORGIN_FRONT or DEQUE_ORGIN_BACK
 *  \return 1: success or 0: fail
 */
int deque_modify(deque_t deque, int index, void* data, int orgin);

/** 
 *  \brief get deque capacity
 *  \param[in] deque: deque handler
 *  \return the capacity of the deque
 */
int deque_capacity(deque_t deque);

/** 
 *  \brief resize the deque
 *  \param[in] deque: deque handler
 *  \param[in] capacity: new capacity of deque
 *  \return 1: success or 0: fail
 */
int deque_alter_capacity(deque_t deque, int capacity);

/** 
 *  \brief modify deque's mode
 *  \param[in] deque: deque handler
 *  \param[in] mode: deque mode
 *  \param[in] set: DEQUE_SET_MODE or DEQUE_RESET_MODE
 *  \return none
 */
void deque_mode(deque_t deque, int mode, int set);

/** 
 *  \brief macro definition method for creating deque
 *  \param[in] type: tpye of item(e.g int char)
 *  \param[in] capacity: capacity of deque
 *  \return deque handler
 */
#define deque(type, capacity)           (deque_create(sizeof(type),(capacity)))

/** 
 *  \brief define a const deque, end use does not need to be deleted
 *  \param[in] type: tpye of item(e.g int char)
 *  \param[in] capacity: capacity of deque
 *  \return const deque
 */
#define const_deque(type, capacity)     &(DEQUE){{4,(type[capacity]){},sizeof(type),0},capacity,0,0,0}

/** 
 *  \brief macro definition method for delete deque
 *  \param[in] deque: deque handler
 *  \return none
 */
#define _deque(deque)                   do{deque_delete(deque);(deque)=NULL;}while(0)

/** 
 *  \brief macro definition method for get front item of deque
 *  \param[in] deque: deque handler
 *  \param[in] type: tpye of item
 *  \param[in] i: index
 *  \return reference to the specified item
 */
#define deque_at(deque, type, i)        (*(type *)deque_data((deque),(i),DEQUE_ORGIN_FRONT))

/** 
 *  \brief macro definition method for get front item of deque
 *  \param[in] deque: deque handler
 *  \param[in] type: tpye of item
 *  \param[in] i: index
 *  \return reference to the specified item
 */
#define deque_front(deque, type, i)     (*(type *)deque_data((deque),(i),DEQUE_ORGIN_FRONT))

/** 
 *  \brief macro definition method for get back item of deque
 *  \param[in] deque: deque handler
 *  \param[in] type: tpye of item
 *  \param[in] i: index
 *  \return reference to the specified item
 */
#define deque_back(deque, type, i)      (*(type *)deque_data((deque),(i),DEQUE_ORGIN_BACK))

#endif
